#ifndef __VTTY_H__
#define __VTTY_H__

#include "vtty_io.h"
#include "vtty_task.h"
#include "vtty_cmd_info.h"

#include <string>
#include <vector>
#include <list>
#include <type_traits>
#include "utools.h"

class VttyTask;
class VttyCommand;
class VttyIOImpl;
class Vtty
{
public:
    Vtty();

    /// @brief 析构函数
    virtual ~Vtty();

    /// @brief 禁止拷贝和赋值
    Vtty(const Vtty &) = delete;
    Vtty &operator=(const Vtty &) = delete;
    Vtty(Vtty &&) = delete;
    Vtty &operator=(Vtty &&) = delete;

    /// @brief 启动vtty
    /// @tparam _VTTYIO_T 输入输出接口类型
    /// @param vtty_io_impl 输入输出接口实例
    /// @param detach_mode 是否使用分离模式，分离模式下，vtty不会启动处理，需要外部调用handler来处理vtty的输入输出
    /// @param parse_task_stack_size 命令解析任务栈大小
    /// @param max_task_count 最大任务数量
    /// @param vttytask_stack_size vtty任务管理栈大小
    /// @param vttyio_in_stack_size vtty输入栈大小
    /// @param vttyio_out_stack_size vtty输出栈大小
    /// @note _VTTYIO_T必须继承自VttyIOImpl
    /// @warning vtty_io_impl必须为指针类型，并且以托管的方式传递给vtty，vtty会在不需要vtty_io_impl进行释放
    template <typename _VTTYIO_T,
              typename = std::enable_if<std::is_base_of<VttyIOImpl, _VTTYIO_T>::value>>
    void begin(_VTTYIO_T *vtty_io_impl,
               bool detach_mode = true, const size_t parse_task_stack_size = 1024,
               const int max_task_count = 20, const size_t vttytask_stack_size = 1024,
               const size_t vttyio_in_stack_size = 1024, const size_t vttyio_out_stack_size = 1024)
    {
        // 启动任务管理功能
        __vtty_task = new VttyTask{this, max_task_count, vttytask_stack_size};

        // 启动收发功能
        __vtty_io_impl = dynamic_cast<VttyIOImpl *>(vtty_io_impl);
        __vtty_io = new VttyIO{*__vtty_io_impl, vttyio_in_stack_size, vttyio_out_stack_size};

        // 配置任务处理模式
        __detach_mode = detach_mode;

        // 启动命令解析功能
        if (detach_mode)
        {
            utcollab::Task(&Vtty::__parsing_scripts, this).detach(parse_task_stack_size); // 分离线程
        }
    }

    /// @brief 启动vtty
    /// @tparam _VTTYIO_T 输入输出接口类型
    /// @param detach_mode 是否使用分离模式，分离模式下，vtty不会启动处理，需要外部调用handler来处理vtty的输入输出
    /// @param parse_task_stack_size 命令解析任务栈大小
    /// @param max_task_count 最大任务数量
    /// @param vttytask_stack_size vtty任务管理栈大小
    /// @param vttyio_in_stack_size vtty输入栈大小
    /// @param vttyio_out_stack_size vtty输出栈大小
    /// @note _VTTYIO_T必须继承自VttyIOImpl
    /// @warning vtty_io_impl必须为指针类型，并且以托管的方式传递给vtty，vtty会在不需要vtty_io_impl进行释放
    template <typename _VTTYIO_T,
              typename = std::enable_if<std::is_base_of<VttyIOImpl, _VTTYIO_T>::value>>
    void begin(bool detach_mode = true, const size_t parse_task_stack_size = 1024,
               const int max_task_count = 20, const size_t vttytask_stack_size = 1024,
               const size_t vttyio_in_stack_size = 1024, const size_t vttyio_out_stack_size = 1024)
    {
        begin(new _VTTYIO_T,
              detach_mode, parse_task_stack_size,
              max_task_count, vttytask_stack_size,
              vttyio_in_stack_size, vttyio_out_stack_size);
    }

    /// @brief 增加一个处理过程，该处理过程会绑定一个命令，当命令被触发时，会执行该处理过程
    /// @param cmd_str 命令的名称
    /// @param cmd_fun 命令的处理过程，由用户自己实现，bind时实例化，ubind时销毁
    /// @param help 命令的帮助信息，使用help查看时，显示此部分信息
    /// @param stack_size 命令处理过程的栈大小
    /// @return 是否成功
    const bool bind_command(
        const std::string &cmd_str,
        const VttyTask::vcmd_create_t cmd_fun,
        const VttyTask::vcmd_help_t help,
        const size_t stack_size);

    template <typename _CMD_TYP,
              typename = std::enable_if<std::is_base_of<VttyCommand, _CMD_TYP>::value>>
    const bool bind_command(const std::string &cmd_str, size_t stack_size = 1024)
    {
        VttyTask::vcmd_create_t cmd_fun = [this](const std::vector<std::string> args_, uint32_t task_id_) -> VttyCommand *
        {
            return dynamic_cast<VttyCommand *>(new _CMD_TYP(this, args_, task_id_));
        };
        return bind_command(cmd_str, cmd_fun, std::bind(&_CMD_TYP::help), stack_size);
    }

    /// @brief 增加一个命令列表
    /// @param _CMD_IDX 命令列表索引
    /// @param Args 命令类型
    /// @param cmd_tpl 命令列表
    template <std::size_t _CMD_IDX = 0, typename... Args>
    void bind_command(const std::tuple<Args...> &cmd_tpl)
    {
        if constexpr (_CMD_IDX < sizeof...(Args))
        {
            auto &cmd_info = std::get<_CMD_IDX>(cmd_tpl);
            using CmdType = typename std::remove_reference<decltype(cmd_info)>::type::cmd_type;
            bind_command<CmdType>(cmd_info.name, cmd_info.stack_size);
            bind_command<_CMD_IDX + 1>(cmd_tpl);
        }
    }

    /// @brief 解除一个处理过程，该处理过程会绑定一个命令，当命令被触发时，会执行该处理过程
    /// @param cmd_str 命令的名称
    /// @return 是否成功
    const bool unbind_command(const std::string &cmd_str);

    /// @brief 判断命令是否已经增加到任务中
    /// @param cmd_str 命令的名称
    /// @return 是否存在
    const bool command_exist(const std::string &cmd_str);

    /// @brief 获取全部命令列表
    /// @return 所有命令状态分别为(名称)
    const std::vector<std::string> command_list() const;

    /// @brief 获取命令帮助信息
    /// @param cmd_str 命令的名称
    /// @return 命令的帮助信息
    const std::string command_help(const std::string &cmd_str) const;

    /// @brief 分离命令和参数，参数根据空格进行分离
    /// @param str 输入的字符串
    /// @return 命令和参数的分离结果
    const std::vector<std::string> split_command_str(const std::string &str);

    /// @brief 执行一条指令
    /// @param cmd_str 指令名称及参数，参数之间使用空格进行分隔
    /// @param args 指令的参数
    /// @return 是否被增加到任务列表中
    const bool exec(const std::string &cmd_str);

    /// @brief 在非分离模式时，提供给外部调用
    /// @note 外部调用时需要保证其其后没有需要处理的任务
    /// @warning 此函数会阻塞，使用时需要注意，如果初始化时的运行模式为分离运行，将直接返回
    void handler();

    // --------提供类似于python的print输出方式--------
    template <typename... Args>
    void print(Args &&...args)
    {
        auto str_data{utfmt::fc_with_ctrl(" ", "", utfmt::to_string(args).c_str()..., nullptr)};
        __vtty_io->print(str_data);
    }

    template <typename... Args>
    void println(Args &&...args)
    {
        auto str_data{utfmt::fc_with_ctrl(" ", "\n", utfmt::to_string(args).c_str()..., nullptr)};
        __vtty_io->print(str_data);
    }

    template <typename... Args>
    void print_direct(Args &&...args)
    {
        auto str_data{utfmt::fc_direct(utfmt::to_string(args).c_str()..., nullptr)};
        __vtty_io->print(str_data);
    }

private:
    bool __running{true};
    bool __detach_mode{true};

    std::vector<VttyTask::cmd_desc_t> __vtty_cmd_arr; // 函数描述列表

    VttyIOImpl *__vtty_io_impl{nullptr};
    VttyIO *__vtty_io{nullptr};
    VttyTask *__vtty_task{nullptr};

    /// @brief 解析相关脚本，并生成命令
    void __parsing_scripts();

    friend class VttyKill;   // kill命令可以进行任务操作
    friend class VttyPS;     // ps命令可以进行任务操作
    friend class VttySignal; // signal命令可以进行任务操作
};

#endif
